package com.prolificinteractive.materialcalendarview;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentState;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;

import com.prolificinteractive.materialcalendarview.MaterialCalendarView.ShowOtherDates;
import com.prolificinteractive.materialcalendarview.ext.Logger2;
import com.prolificinteractive.materialcalendarview.format.DayFormatter;
import com.prolificinteractive.materialcalendarview.spans.DotSpan;

import org.threeten.bp.format.DateTimeFormatter;

import java.util.ArrayList;
import java.util.List;

import static com.prolificinteractive.materialcalendarview.MaterialCalendarView.showDecoratedDisabled;
import static com.prolificinteractive.materialcalendarview.MaterialCalendarView.showOtherMonths;
import static com.prolificinteractive.materialcalendarview.MaterialCalendarView.showOutOfRange;

/**
 * Display one day of a {@linkplain MaterialCalendarView}
 */
public class DayView extends Text implements Component.EstimateSizeListener, Component.DrawTask, Component.ComponentStateChangedListener {

    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, d MMM yyyy");
    private CalendarDay date;
    private int selectionColor = Color.BLUE.getValue();
    private final Paint paint = new Paint();
    private final static int FADE_TIME = 300;
    private Element customBackground = null;
    private Element selectionDrawable;

    private DayFormatter formatter = DayFormatter.DEFAULT;
    private DayFormatter contentDescriptionFormatter = formatter;

    private boolean isInRange = true;
    private boolean isInMonth = true;
    private boolean isDecoratedDisabled = false;
    private int showOtherDates = ShowOtherDates.SHOW_DEFAULTS.value;
    DayViewFacade facadeoher;
    private int state;

    private boolean isChecked = false;
    MaterialCalendarView view;
    public DayView(Context context, MaterialCalendarView view, CalendarDay day) {
        super(context);
        setSelectionColor(this.selectionColor);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL_STYLE);
        setTextAlignment(TextAlignment.CENTER);
        setDay(day);
        setTextSize(AttrHelper.fp2px(12, getContext()));
        addDrawTask(this, DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        setComponentStateChangedListener(this);
        setEstimateSizeListener(this);
        this.view = view;
    }

    @Override
    public void setTextSize(int size, TextSizeType textSizeType) {
        super.setTextSize(size, textSizeType);
    }

    public void setDay(CalendarDay date) {
        this.date = date;
        setText(getLabel());
    }

    /**
     * Set the new label formatter and reformat the current label. This preserves current spans.
     *
     * @param formatter new label formatter
     */
    public void setDayFormatter(DayFormatter formatter) {
        this.contentDescriptionFormatter = contentDescriptionFormatter == this.formatter ?
            formatter : contentDescriptionFormatter;
        this.formatter = formatter == null ? DayFormatter.DEFAULT : formatter;
//        CharSequence currentLabel = getText();
//        Object[] spans = null;
//        if (currentLabel instanceof Spanned) {
//            spans = ((Spanned) currentLabel).getSpans(0, currentLabel.length(), Object.class);
//        }
//        SpannableString newLabel = new SpannableString(getLabel());
//        if (spans != null) {
//            for (Object span : spans) {
//                newLabel.setSpan(span, 0, newLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//            }
//        }
//        setText(newLabel);
        setText(getLabel());
    }

    /**
     * Set the new content description formatter and reformat the current content description.
     *
     * @param formatter new content description formatter
     */
    public void setDayFormatterContentDescription(DayFormatter formatter) {
        this.contentDescriptionFormatter = formatter == null ? this.formatter : formatter;
//        setContentDescription(getContentDescriptionLabel());
    }


    public String getLabel() {
        return formatter.format(date);
    }

    public void setSelectionColor(int color) {
        this.selectionColor = color;
        paint.setColor(new Color(selectionColor));
        generateBackground(selectionColor, FADE_TIME);
    }

    /**
     * setSelectionDrawable
     *
     * @param drawable custom selection drawable
     */
    public void setSelectionDrawable(Element drawable) {
        this.selectionDrawable = drawable;
        generateBackground(selectionColor, FADE_TIME);
    }

    /**
     * setCustomBackground
     *
     * @param drawable background to draw behind everything else
     */
    public void setCustomBackground(Element drawable) {
        if (drawable == null) {
            this.customBackground = null;
        } else {
            this.customBackground = drawable;
        }
        if (customBackground != null) {
            customBackground.setBounds(tempRect);
        }
    }

    public CalendarDay getDate() {
        return date;
    }

    private void setEnabled() {
        boolean enabled = isInMonth && isInRange && !isDecoratedDisabled;
        super.setEnabled(isInRange && !isDecoratedDisabled);
        boolean showOtherMonths = showOtherMonths(showOtherDates);
        boolean showOutOfRange = showOutOfRange(showOtherDates) || showOtherMonths;
        boolean showDecoratedDisabled = showDecoratedDisabled(showOtherDates);
        boolean shouldBeVisible = enabled;
        if (!isInMonth && showOtherMonths) {
            shouldBeVisible = true;
        }
        if (!isInRange && showOutOfRange) {
            shouldBeVisible |= isInMonth;
        }
        if (isDecoratedDisabled && showDecoratedDisabled) {
            shouldBeVisible |= isInMonth && isInRange;
        }
        if (!isInMonth && shouldBeVisible) {
            if (!isEnabled()) {
                setTextColor(Color.GRAY);
            }
        }
        if (isDecoratedDisabled) {
            setTextColor(Color.GRAY);
        }
        setVisibility(shouldBeVisible ? Component.VISIBLE : Component.INVISIBLE);
    }

    protected void setupSelection(int showOtherDates, boolean inRange, boolean inMonth) {
        this.showOtherDates = showOtherDates;
        this.isInMonth = inMonth;
        this.isInRange = inRange;
        setEnabled();
    }

    private final Rect tempRect = new Rect();
    private final Rect circleDrawableRect = new Rect();
    private List<DayViewFacade.Span> spans = new ArrayList<>();

    @Override
    public void setBackground(Element element) {
        super.setBackground(element);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (state == ComponentState.COMPONENT_STATE_PRESSED) {
            if (customBackground != null) {
                if (getWidth() > getHeight()) {
                    customBackground.setBounds((getWidth() - getHeight()) / 2, 0, getHeight() + (getWidth() - getHeight()) / 2, getHeight());
                    customBackground.drawToCanvas(canvas);
                } else {
                    customBackground.setBounds(0, (getHeight() - getWidth()) / 2, getWidth(), getWidth() + (getHeight() - getWidth()) / 2);
                    customBackground.drawToCanvas(canvas);
                }
            }
            if (selectionDrawable != null) {
                if (getWidth() > getHeight()) {
                    selectionDrawable.setBounds((getWidth() - getHeight()) / 2, 0, getHeight() + (getWidth() - getHeight()) / 2, getHeight());
                    selectionDrawable.drawToCanvas(canvas);
                } else {
                    selectionDrawable.setBounds(0, (getHeight() - getWidth()) / 2, getWidth(), getWidth() + (getHeight() - getWidth()) / 2);
                    selectionDrawable.drawToCanvas(canvas);
                }
                return;
            }
            if (getWidth() > getHeight()) {
                canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getHeight() / 2f, paint);
            } else {
                canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getWidth() / 2f, paint);
            }

        } else {
            if (customBackground != null) {
                if (getWidth() > getHeight()) {
                    customBackground.setBounds((getWidth() - getHeight()) / 2, 0, getHeight() + (getWidth() - getHeight()) / 2, getHeight());
                    customBackground.drawToCanvas(canvas);
                } else {
                    customBackground.setBounds(0, (getHeight() - getWidth()) / 2, getWidth(), getWidth() + (getHeight() - getWidth()) / 2);
                    customBackground.drawToCanvas(canvas);
                }
            }
            if (spans != null && spans.size() > 0) {
                for (DayViewFacade.Span span : spans) {
                    Object span1 = span.span;
                    if (span1 instanceof DotSpan) {
                        Logger2.out("--------->" + getDate());
                        DotSpan textSpan = (DotSpan) span1;
                        textSpan.drawBackground(canvas, new Paint(), this);
                    }
                }
            }
            if (isChecked) {
                if (selectionDrawable != null) {
                    if (getWidth() > getHeight()) {
                        selectionDrawable.setBounds((getWidth() - getHeight()) / 2, 0, getHeight() + (getWidth() - getHeight()) / 2, getHeight());
                        selectionDrawable.drawToCanvas(canvas);
                    } else {
                        selectionDrawable.setBounds(0, (getHeight() - getWidth()) / 2, getWidth(), getWidth() + (getHeight() - getWidth()) / 2);
                        selectionDrawable.drawToCanvas(canvas);
                    }
                } else {
                    if (getWidth() > getHeight()) {
                        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getHeight() / 2f, paint);
                    } else {
                        canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, getWidth() / 2f, paint);
                    }
                }
                if (view.getBigSize()) {
                    setTextSize(AttrHelper.fp2px(20, getContext()));
                }
            }
        }
    }

    private void generateBackground(int color, int fadeTime) {
        StateElement drawable = new StateElement();
        drawable.setExitFadeDuration(fadeTime);
//        if (selectionDrawable != null) {
//            drawable.addState(new int[]{ComponentState.COMPONENT_STATE_PRESSED}, selectionDrawable);
//        } else {
//            drawable.addState(new int[]{ComponentState.COMPONENT_STATE_PRESSED}, generateCircleDrawable(color));
//        }
//        drawable.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY},
//            generateCircleDrawable(Color.TRANSPARENT.getValue()));
//        setBackground(drawable);
        invalidate();
    }

    private Element generateCircleDrawable(final int color) {
        ShapeElement drawable = new ShapeElement();
        drawable.setRgbColor(RgbColor.fromArgbInt(color));
        drawable.setShape(ShapeElement.OVAL);
        drawable.setBounds(tempRect);
        return drawable;
    }

    /**
     * applyFacade
     *
     * @param facade facade
     * @param font font
     */
    void applyFacade(DayViewFacade facade, Font font) {
//        this.isBig = isBig;
        if (facade == null) {
            facade = facadeoher;
        }
        spans.clear();
        facadeoher = facade;
        spans.addAll(facade.getSpans());
        this.isDecoratedDisabled = facade.areDaysDisabled();
        setEnabled();
        setCustomBackground(facade.getBackgroundDrawable());
        setSelectionDrawable(facade.getSelectionDrawable());

        // Facade has spans
//        if (!spans.isEmpty()) {
//            String label = getLabel();
//            SpannableString formattedLabel = new SpannableString(getLabel());
//            for (DayViewFacade.Span span : spans) {
//                formattedLabel.setSpan(span.span, 0, label.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
//            }
//            setText(formattedLabel);
//        }
//        // Reset in case it was custo 8mized previously
//        else {
        if (font != null) {
            setFont(font);
            setTextSize(AttrHelper.fp2px(14, getContext()));
        }
        setText(getLabel());
//        }
    }


    @Override
    public boolean onEstimateSize(int i, int i1) {
        int w = EstimateSpec.getSize(i);
        int h = EstimateSpec.getSize(i1);
        calculateBounds(w, h);
        setEstimatedSize(EstimateSpec.getSizeWithMode(w, i), EstimateSpec.getSizeWithMode(h, i1));
        return true;
    }

    private void calculateBounds(int width, int height) {
        final int radius = Math.min(height, width);
        final int offset = Math.abs(height - width) / 2;
        // Lollipop platform bug. Circle drawable offset needs to be half of normal offset
        //        final int circleOffset =
//            Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP ? offset / 2 : offset;
        if (width >= height) {
            tempRect.set(offset, 0, radius + offset, height);
            circleDrawableRect.set(offset, 0, radius + offset, height);
        } else {
            tempRect.set(0, offset, width, radius + offset);
            circleDrawableRect.set(0, offset, width, radius + offset);
        }
    }

    private boolean canTouch = true;

    public boolean isCanTouch() {
        return canTouch;
    }

    public void setCanTouch(boolean canTouch) {
        this.canTouch = canTouch;
    }

    public void setChecked(boolean isChecked) {
        if (!isCanTouch()) {
            return;
        }
        this.isChecked = isChecked;
        if (isChecked) {
            setTextColor(Color.WHITE);
            if (facadeoher != null) {
                setTextSize(AttrHelper.fp2px(15, getContext()));
            } else {
                setTextSize(AttrHelper.fp2px(12, getContext()));
            }
        } else {
            setTextSize(AttrHelper.fp2px(12, getContext()));
            if (isInMonth) {
                if (isInRange) {
                    if (isDecoratedDisabled) {
                        setTextColor(Color.GRAY);
                    } else {
                        if(view.isOldStyle()&&FORMATTER.format(getDate().getDate()).equals(FORMATTER.format(CalendarDay.today().getDate()))){
                            setTextColor(Color.BLUE);
                        }else{
                            setTextColor(Color.BLACK);
                        }
                    }
                } else {
                    setTextColor(Color.GRAY);
                }
            } else {
                setTextColor(Color.GRAY);
            }

        }
        invalidate();
    }

    public boolean isChecked() {
        return this.isChecked;
    }

    @Override
    public void onComponentStateChanged(Component component, int i) {

        state = ComponentState.COMPONENT_STATE_EMPTY;
        if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_PRESSED, i)) {
            state = ComponentState.COMPONENT_STATE_PRESSED;
        } else if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_HOVERED, i)) {
            state = ComponentState.COMPONENT_STATE_HOVERED;
        } else if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_EMPTY, i)) {
            state = ComponentState.COMPONENT_STATE_EMPTY;
        } else if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_CHECKED, i)) {
            state = ComponentState.COMPONENT_STATE_CHECKED;
        } else if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_DISABLED, i)) {
            state = ComponentState.COMPONENT_STATE_DISABLED;
        } else if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_FOCUSED, i)) {
            state = ComponentState.COMPONENT_STATE_FOCUSED;
        } else if (ComponentState.isStateMatched(ComponentState.COMPONENT_STATE_SELECTED, i)) {
            state = ComponentState.COMPONENT_STATE_SELECTED;
        }
        invalidate();

    }
}
